Dis-(And Re-)assembling The Default Windows Phone YouTube Library
Windows Phone 7 comes with built-in support for YouTube. The system has a dedicated URI scheme registered for it, and I talked about it a while ago. It is pretty cool if the developer knows the URI scheme so that the application can be initiated from inside another application, but it is even cooler to disassemble the default YouTube application itself and attempt to integrate Microsoft-built capabilities in your own application.
With a bit of work with Wireshark I managed to get YouTubeLite.dll
that comes with the default YouTube application. This is the core of the application itself – offering access to many capabilities of the YouTube service through a managed layer.
Image lost since transition to new blog
Needless to say, the library has some interesting gems in it. For example:
Image lost since transition to new blog
As you probably know, YouTube doesn’t have a direct public API that would allow video streaming, so this is an interesting component to work with. The library itself is useless by default in an application that has it as a reference. There is additional work involved with adding a config.dat
file that will be used as a starting point for the API initialization. Without it I was constantly getting NullReferenceException
(s) and this was not something I could avoid easily.
Also, since I didn’t have the appropriate symbols, I could not debug the library to the level I wanted, and that was an issue from the very beginning, since all I could do was poking around – there is no documentation on this whatsoever.
That being said, I decided to re-compile the necessary parts of the library. I fired up Reflector and downloaded the FileGenerator plugin, so that I won’t have to copy-paste for the rest of my day. I ended up with the C# implementations of all classes that were needed for full-fledged API invocation.
Image lost since transition to new blog
Neat, but not yet there. The default results contained many instances of fields named something like private string <Id>k__BackingField
, so I decided to go ahead and rename all those to meaningful names. Ten minutes later I had a compiled clean version of YouTubeLite.
I created a sample Windows Phone application and referenced the re-compiled project.
Image lost since transition to new blog
When the YouTube API is invoked with the YouTubeLite library, the device needs to be registered. The device ID and the developer API key are used to create two files in the isolated storage: DeviceId.dat
and DeviceKey.dat
. These will be used for many other calls and if the device is not registered, most of the YouTubeLite methods will fail.
So when my application launches, I am calling EnsureDeviceRegistered
:
YouTubeLite.Models.YouTubePrivateAPI.EnsureDeviceRegistered(new EventHandler(GetData));
private void GetData(object sender, EventArgs e)
{
Debug.WriteLine("Registration completed.");
}
This will do all the work for me. After I do this, I can check whether the process was successful or not:
Debug.WriteLine(YouTubeLite.Models.YouTubePrivateAPI.DeviceRegistered);
Once I am sure that the device is registered, I can use a YouTube client instance to retrieve data about various videos. The class itself is a singleton, so I have to instantiate it like this:
YouTubeLite.Models.YouTubeClient client = YouTubeLite.Models.YouTubeClient.Instance;
By calling GetVideoFromId
I can get an instance of VideoModel
with video data. For example:
YouTubeLite.Models.VideoModel m;
m = client.GetVideoFromId(new YouTubeLite.Models.VideoId("3ZIERqHK780"), new YouTubeLite.Models.PlayVideoCallBack(GetVideo), out fsync);
Notice that I am passing a PlayVideoCallback
that is represented by the GetVideo method. This is triggered once the VideoModel
is obtained and its data is accessible.
private void GetVideo(Exception ex)
{
Debug.WriteLine(m.Title);
}
For this snippet I am using the video of Barack Obama, the President of the United States, delivering his weekly address. The ID I am passing (3ZIERqHK780) is the video ID one would use in the browser after the v parameter.
There is a sample page in my project, that has the following layout:
<Grid x:Name="LayoutRoot" Background="Transparent">
<TextBlock x:Name="TitleText" TextWrapping="Wrap" FontSize="28" Height="80" Margin="20,0,20,640"></TextBlock>
<Image x:Name="ThumbnailImage" Height="290" Margin="20,0,20,240"></Image>
</Grid>
As simple as it can be. Now, when the VideoModel
instance is loaded, I can simply assign the respective properties for existing controls:
private void GetVideo(Exception ex)
{
TitleText.Text = m.Title;
ThumbnailImage.Source = new BitmapImage(m.BestThumbnail.ContentUri);
}
And I will get this result:
Image lost since transition to new blog
Great. This is the basic metadata obtained through the request. What about the video itself? The VideoModel
exposes three different URIs (the last one is usually null)":
- MediaContentFormat2 – 3GP video
- MediaContentFormat3 – MP4 video
- MediaContentFormat9
I don’t like 3GP video – its quality is fairly bad, so why not look straight at the MP4 video then? That’s exactly what I am going to do, and before I go back in the code-behind, I need to add one more component to the main work page – a MediaElement
, that will play the video.
<MediaElement x:Name="MediaPlayerElement" Height="270" Margin="20,340,20,0"></MediaElement>
And in code-behind, I will only need to modify the GetVideo method to set the source and state for MediaPlayerElement:
private void GetVideo(Exception ex)
{
TitleText.Text = m.Title;
ThumbnailImage.Source = new BitmapImage(m.BestThumbnail.ContentUri);
MediaPlayerElement.Source = m.MediaContentUriFormat3;
MediaPlayerElement.Play();
}
IMPORTANT NOTE: The emulator doesn’t support MP4 video, so this was tested on an actual Windows Phone device.
Image lost since old blog.
Ultimately, this way I can:
- Stream videos
- Download videos
Both possible because I get the actual video URL. And with enough information (e.g. video feed from YouTube) I can easily build an alternative YouTube application (there is one already, by the way) as long as I have access to video IDs.
PS: There is a helper class present in the same library, called UriParser
, that allows me to extract video IDs from any YouTube URL.